package haxeframe.utils;

class MathUtils
{
	private static var EPSILON:Float = 0.0000000001;
	public static var DEGREES_TO_RADIANS:Float = 0.0174532925;
	public static var RADIANS_TO_DEGREES:Float = 57.2957795785;
	
	public static function evaluateString(s:String):Float
	{
		var parts:Array<Dynamic> = new Array<Dynamic>();
		var numbers:Array<Dynamic> = new Array<Dynamic>();
		var operators:Array<Dynamic> = new Array<Dynamic>();
		
		var part:String = '';
		var newString:String = '';
		
		for(i in 0...s.length){
			
			var c:String = s.charAt(i);
			
			switch(c){
				
				case '(' :
					var ss:String = '';
					var j:Int = i;
					while(c != ')'){
						++j;
						c = s.charAt(j);
						if(c == '('){
							throw 'Nested parentheses are not supported : '+s;
						}
						if(c != ')') ss += c;
					}
					var nested:Float = evaluateString(ss);
					newString += nested;
					break;
				
				default :
					newString += c;
					
			}
		}
		
		var operator:Bool = false;
		
		for(i in 0...newString.length){
			
			var c:String = newString.charAt(i);
			
			switch(c){
				
				case '/' :
					operators.push('/');
					parts.push(part);
					part = '';
					operator = true;
					break;
				
				case '*' :
					operators.push('*');
					parts.push(part);
					part = '';
					operator = true;
					break;
				
				case '-' :
					if(operator){
						part += '-';
					} else {
						operators.push('-');
						parts.push(part);
						part = '';
					}
					operator = true;
					break;
				
				case '+' :
					operators.push('+');
					parts.push(part);
					part = '';
					operator = true;
					break;
				
				default :
					if('0123456789'.indexOf(c) > -1 || c == '.'){
						part += c;
						operator = false;
					} else if(c != ' '){
						throw 'String provided contains illegal character: '+c;
					}
					
			}
			
			if(i == newString.length-1 && part != '' && c != ')'){
				parts.push(part);
			}
		}
		
		var newParts:Array<Dynamic> = newString.split(' ');
		
		var value:Float = 0;
		var o:Int = 0;

		var num:Float = Std.parseFloat(part);
		var op:String = operators[o];
		var other:Float;
		
		for(j in 0...newParts.length)
		{
			var i:Int = j;
			part = newParts[i];
			

				switch(op){
					
					case '/' :
						if(i+1 >= newParts.length){
							other = Std.parseFloat(newParts.splice(i,1)[0]);
							newParts[i-1] = newParts[i-1]/other;
						} else {
							other = Std.parseFloat(newParts.splice(i+1,1)[0]);
							newParts[i] = num/other;
							if(i > 0) --i;
							if(i > 0) --i;
						}
						break;
					
					case '*' :
						if(i+1 >= newParts.length){
							other = Std.parseFloat(newParts.splice(i,1)[0]);
							newParts[i-1] = newParts[i-1]*other;
						} else {
							other = Std.parseFloat(newParts.splice(i+1,1)[0]);
							newParts[i] = num*other;
							if(i > 0) --i;
							if(i > 0) --i;
						}
						break;
					
				}
				++o;
		}
		
		o = 0;
		value = Std.parseFloat(newParts[0]);

		for(i in 0...newParts.length){
			part = newParts[i];
			num = Std.parseFloat(part);


				op = operators[o];
				
				switch(op){
					
					case '+' :
						value += num;
						break;
					
					case '-' :
						value -= num;
						break;
				}
				++o;
		}

		return value;
		
	}
	
	// public static function hexToInteger(hex:Float):Int
	// {
	// 	var integer:Int = Std.int(hex);
	// 	return integer;
	// }
	
	// public static function integerToHex(integer:Int):String
	// {
	// 	return "0x" + untyped integer.toString(16);
	// }
	
	// public static function hexToRGB(hex:Int):Dynamic{
	// 	var rgbObj:Dynamic = {
	// 		red: ((hex & 0xFF0000) >> 16),
	// 		green: ((hex & 0x00FF00) >> 8),
	// 		blue: ((hex & 0x0000FF))
	// 	};
		
	// 	return rgbObj;
	// }
	
	// public static function RGBToHex(r:Int, g:Int, b:Int):Float
	// {
	// 		return r << 16 | g << 8 | b;
	// }
	
	// calculate area of the contour polygon
	// public static function area(contour:Array<Dynamic>):Float{
	// 	var n:Int = contour.length;
	// 	var a:Float  = 0.0;
	// 	var p:Int = 0;
	// 	for(q in 0...n){
	// 		if(p == 0){
	// 			p = n-1;
	// 		} else {
	// 			p = q;
	// 		}
	// 		a += contour[p].x * contour[q].y - contour[q].x * contour[p].y;
	// 	}
	// 	return a * 0.5;
	// }
	
	// public static function triangulate(contour:Array<Dynamic>):Array<Dynamic>
	// {
	// 	var result:Array<Dynamic> = new Array<Dynamic>();
	// 	var n:Int = contour.length;
	// 	if ( n < 3 ) return null;
		
	// 	var verts:Array<Dynamic> = new Array<Dynamic>();
		
	// 	/* we want a counter-clockwise polygon in verts */
	// 	var v:Int;
		
	// 	if ( 0.0 < area(contour) ){
	// 		for (v in 0...n) verts[v] = v;
	// 	}else{
	// 		for(v in 0...n) verts[v] = (n-1)-v;
	// 	}
		
	// 	var nv:Int = n;
		
	// 	/*  remove nv-2 vertsertices, creating 1 triangle every time */
	// 	var count:Int = 2*nv;   /* error detection */
	// 	var m:Int = 0;
	// 	for(i in 0...nv-1)
	// 	{
	// 		var v:Int = i;
	// 		if(nv > 2){
	// 			/* if we loop, it is probably a non-simple polygon */
	// 			if (0 >= (count--)){
	// 				//** Triangulate: ERROR - probable bad polygon!
	// 				// trace("bad poly");
	// 				return null;
	// 			}
				
	// 			/* three consecutive vertices in current polygon, <u,v,w> */
	// 			var u:Int = v; if (nv <= u) u = 0;     /* previous */
	// 			v = u+1; if (nv <= v) v = 0;     /* new v    */
	// 			var w:Int = v+1; if (nv <= w) w = 0;     /* next     */
				
	// 			if ( snip(contour,u,v,w,nv,verts)){
	// 				var a:Int,b:Int,c:Int,s:Int,t:Int;
					
	// 				/* true names of the vertices */
	// 				a = verts[u]; b = verts[v]; c = verts[w];
					
	// 				/* output Triangle */
	// 				result.push( contour[a] );
	// 				result.push( contour[b] );
	// 				result.push( contour[c] );
					
	// 				m++;
					
	// 				/* remove v from remaining polygon */
	// 				s=v;
	// 				t=v+1;
	// 				for(t in 0...nv){
	// 					verts[s] = verts[t]; 
	// 					nv--;
	// 					++s;
	// 				}
					
	// 				/* resest error detection counter */
	// 				count = 2 * nv;
	// 			}
	// 		}
	// 	}
		
	// 	return result;
	// }
	
	// private static function snip(contour:Array<Dynamic>, u:Int, v:Int, w:Int, n:Int, verts:Array<Dynamic>):Bool{
	// 	var p:Int;
	// 	var ax:Float, ay:Float, bx:Float, by:Float;
	// 	var cx:Float, cy:Float, px:Float, py:Float;
		
	// 	ax = contour[verts[u]].x;
	// 	ay = contour[verts[u]].y;
		
	// 	bx = contour[verts[v]].x;
	// 	by = contour[verts[v]].y;
		
	// 	cx = contour[verts[w]].x;
	// 	cy = contour[verts[w]].y;
		
	// 	if ( EPSILON > (((bx-ax)*(cy-ay)) - ((by-ay)*(cx-ax))) ) return false;
		
	// 	for (p in 0...n){
	// 		if( (p == u) || (p == v) || (p == w) ) continue;
	// 		px = contour[verts[p]].x;
	// 		py = contour[verts[p]].y;
	// 		if (insideTriangle(ax,ay,bx,by,cx,cy,px,py)) return false;
	// 	}
	// 	return true;
	// }
	
	// see if p is inside triangle abc
	// private static function insideTriangle(	ax:Float, ay:Float,
	// 										bx:Float, by:Float,
	// 										cx:Float, cy:Float,
	// 										px:Float, py:Float):Bool{
		
	// 	var aX:Float, aY:Float, bX:Float, bY:Float;
	// 	var cX:Float, cY:Float, apx:Float, apy:Float;
	// 	var bpx:Float, bpy:Float, cpx:Float, cpy:Float;
	// 	var cCROSSap:Float, bCROSScp:Float, aCROSSbp:Float;
		
	// 	aX = cx - bx;
	// 	aY = cy - by;
	// 	bX = ax - cx;
	// 	bY = ay - cy;
	// 	cX = bx - ax;
	// 	cY = by - ay;
	// 	apx= px  -ax;
	// 	apy= py - ay;
	// 	bpx= px - bx;
	// 	bpy= py - by;
	// 	cpx= px - cx;
	// 	cpy= py - cy;
		
	// 	aCROSSbp = aX*bpy - aY*bpx;
	// 	cCROSSap = cX*apy - cY*apx;
	// 	bCROSScp = bX*cpy - bY*cpx;
		
	// 	return ((aCROSSbp >= 0.0) && (bCROSScp >= 0.0) && (cCROSSap >= 0.0));
	// }
}